import 'dart:async';
import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:view_lamp/custom/preview_container.dart';

import 'preview_action_script.dart';

class LightStringPreview extends StatefulWidget {
  ///transformDuration == 0 时为跳变，否则按时间渐变
  // final Duration transformDuration;

  ///转换时间间隔（包含转换时长，所以需大于transformDuration）
  // final Duration duration;
  final PreviewActionScript script;

  LightStringPreview(this.script,
      {Key key,
      // this.duration = const Duration(milliseconds: 500),
      // this.transformDuration = const Duration(seconds: 0)
     })
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _LightStringPreviewState();
}

class _LightStringPreviewState extends State<LightStringPreview>
    with TickerProviderStateMixin {
  Timer timer;
  double viewWidth = 0.0;
  double viewHeight = 0.0;
  AnimationController animationController;
  Animation animation;
  LampsTween tween;
  List<Color> bgColors;

  @override
  void initState() {
    super.initState();

    animationController =
        AnimationController(vsync: this, duration: Duration(seconds: 0));

    bgColors = widget.script.getColorList();
    animation = LampsTween(Lamps.empty(), Lamps.randomFromColors(bgColors))
        .animate(animationController);
    animationController.forward();

    timer = Timer.periodic(widget.script.duration??Duration(seconds: 1), (Timer t) => _changeColors());
  }

  _changeColors() {
    timer.cancel();
    setState(() {
      var colorList = widget.script.getColorList();
      var tempList = colorList.map((e) => e).toList();
      animationController =
          AnimationController(vsync: this, duration: widget.script.transformDuration??Duration(seconds: 0));
      animationController.addStatusListener(_controllerStateChanged);
      animation = LampsTween(animation.value, Lamps(tempList))
          .animate(animationController);
      animationController.forward(from: 0.0);
    });
  }

  _controllerStateChanged(AnimationStatus status){
    if(status == AnimationStatus.completed){
      animationController.removeStatusListener(_controllerStateChanged);
      animationController.dispose();
      timer = Timer.periodic(widget.script.duration??Duration(seconds: 1), (Timer t) => _changeColors());
    }
  }

  @override
  void dispose() {
    animationController.dispose();
    timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (viewWidth == 0) {
      /// 延时一下,需要等state layout结束之后才能获取size
      Future.delayed(Duration(milliseconds: 100), () {
        setState(() {
          viewWidth =
              context?.findRenderObject()?.paintBounds?.size?.width ?? 0;
          if (viewWidth > 0) {
            viewHeight = viewWidth * 2 / 8;
          }
        });
      });
    }
    return
      Container(
        width: double.infinity,
        child: Column(
        children: [
          AnimatedBuilder(
              animation: animation,
              builder: (BuildContext context, Widget child) {
                return PreviewContainer(animation, viewWidth, viewHeight);
              }),
        ],
    ),
      );
  }
}

class Lamps {
  final List<Color> lampColors;

  Lamps(this.lampColors);

  factory Lamps.empty() {
    List<Color> list = List.generate(12, (index) => Colors.black);
    return Lamps(list);
  }

  factory Lamps.randomFromColors(List<Color> colors) {
    List<Color> list =
        List.generate(12, (index) => colors[Random().nextInt(colors.length)]);
    return Lamps(list);
  }

  static Lamps lerp(Lamps begin, Lamps end, double t) {
    final lampColors = List.generate(
        12,
        (index) => Color.lerp(
            begin._lampColorOrNull(index) ?? Colors.transparent,
            end._lampColorOrNull(index) ?? Colors.transparent,
            t));

    return Lamps(lampColors);
  }

  Color _lampColorOrNull(int index) =>
      (index < lampColors.length ? lampColors[index] : null);
}

class LampsTween extends Tween<Lamps> {
  LampsTween(Lamps begin, Lamps end) : super(begin: begin, end: end);

  @override
  Lamps lerp(double t) => Lamps.lerp(begin, end, t);
}

